<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css" integrity="sha256-2H3fkXt6FEmrReK448mDVGKb3WW2ZZw35gI7vqHOE4Y=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{&quot;hostname&quot;:&quot;www.nilstorm.com&quot;,&quot;root&quot;:&quot;&#x2F;&quot;,&quot;images&quot;:&quot;&#x2F;images&quot;,&quot;scheme&quot;:&quot;Gemini&quot;,&quot;version&quot;:&quot;8.5.0&quot;,&quot;exturl&quot;:false,&quot;sidebar&quot;:{&quot;position&quot;:&quot;left&quot;,&quot;display&quot;:&quot;post&quot;,&quot;padding&quot;:18,&quot;offset&quot;:12},&quot;copycode&quot;:false,&quot;bookmark&quot;:{&quot;enable&quot;:false,&quot;color&quot;:&quot;#222&quot;,&quot;save&quot;:&quot;auto&quot;},&quot;fancybox&quot;:false,&quot;mediumzoom&quot;:false,&quot;lazyload&quot;:false,&quot;pangu&quot;:false,&quot;comments&quot;:{&quot;style&quot;:&quot;tabs&quot;,&quot;active&quot;:null,&quot;storage&quot;:true,&quot;lazyload&quot;:false,&quot;nav&quot;:null},&quot;motion&quot;:{&quot;enable&quot;:true,&quot;async&quot;:false,&quot;transition&quot;:{&quot;post_block&quot;:&quot;fadeIn&quot;,&quot;post_header&quot;:&quot;fadeInDown&quot;,&quot;post_body&quot;:&quot;fadeInDown&quot;,&quot;coll_header&quot;:&quot;fadeInLeft&quot;,&quot;sidebar&quot;:&quot;fadeInUp&quot;}},&quot;prism&quot;:false,&quot;i18n&quot;:{&quot;placeholder&quot;:&quot;Searching...&quot;,&quot;empty&quot;:&quot;We didn&#39;t find any results for the search: ${query}&quot;,&quot;hits_time&quot;:&quot;${hits} results found in ${time} ms&quot;,&quot;hits&quot;:&quot;${hits} results found&quot;}}</script><script src="/js/config.js"></script>
<meta name="description" content="简介单元测试是先mock一些正常边界异常条件来对接口进行操作，并且期望接口返回什么内容，最后接口实现了之后再重新测试一遍。TDD：Test-Driven Development，测试驱动开发模式——旨在强调在开发功能代码之前，先编写测试代码。开发未动，测试先行。">
<meta property="og:type" content="article">
<meta property="og:title" content="关于Java单元测试，你需要知道的一切">
<meta property="og:url" content="http://www.nilstorm.com/2017/3.698e+119.html">
<meta property="og:site_name" content="Lam&#39;s Blog">
<meta property="og:description" content="简介单元测试是先mock一些正常边界异常条件来对接口进行操作，并且期望接口返回什么内容，最后接口实现了之后再重新测试一遍。TDD：Test-Driven Development，测试驱动开发模式——旨在强调在开发功能代码之前，先编写测试代码。开发未动，测试先行。">
<meta property="og:locale">
<meta property="og:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk12.png">
<meta property="og:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk13.png">
<meta property="og:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk14.png">
<meta property="og:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk15.png">
<meta property="og:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk16.png">
<meta property="og:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk17.png">
<meta property="og:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk18.png">
<meta property="og:image" content="https://tva1.sinaimg.cn/large/007S8ZIlgy1gee6wkfo69j30e9026gm4.jpg">
<meta property="article:published_time" content="2017-03-04T05:54:47.000Z">
<meta property="article:modified_time" content="2021-06-06T08:08:18.173Z">
<meta property="article:author" content="LinBinghe">
<meta property="article:tag" content="Java">
<meta property="article:tag" content="单元测试">
<meta property="article:tag" content="Junit">
<meta property="article:tag" content="Mock">
<meta property="article:tag" content="覆盖率">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk12.png">


<link rel="canonical" href="http://www.nilstorm.com/2017/3.698e+119.html">



<script class="next-config" data-name="page" type="application/json">{&quot;sidebar&quot;:&quot;&quot;,&quot;isHome&quot;:false,&quot;isPost&quot;:true,&quot;lang&quot;:&quot;zh-Hans&quot;,&quot;comments&quot;:true,&quot;permalink&quot;:&quot;http:&#x2F;&#x2F;www.nilstorm.com&#x2F;2017&#x2F;3.698e+119.html&quot;,&quot;path&quot;:&quot;2017&#x2F;3.698e+119.html&quot;,&quot;title&quot;:&quot;关于Java单元测试，你需要知道的一切&quot;}</script>

<script class="next-config" data-name="calendar" type="application/json">&quot;&quot;</script>
<title>关于Java单元测试，你需要知道的一切 | Lam's Blog</title>
  




  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<link rel="alternate" href="/atom.xml" title="Lam's Blog" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar" role="button">
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">Lam's Blog</h1>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">Knowledge as Action</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>







</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E7%AE%80%E4%BB%8B"><span class="nav-number">1.</span> <span class="nav-text">简介</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#JUNIT"><span class="nav-number">2.</span> <span class="nav-text">JUNIT</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%89%B9%E6%80%A7"><span class="nav-number">2.1.</span> <span class="nav-text">特性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9F%BA%E6%9C%AC%E6%B5%81%E7%A8%8B"><span class="nav-number">2.2.</span> <span class="nav-text">基本流程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%89%96%E6%9E%90%E6%A6%82%E5%BF%B5"><span class="nav-number">2.3.</span> <span class="nav-text">剖析概念</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#TestXXX"><span class="nav-number">2.3.1.</span> <span class="nav-text">TestXXX</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Assert%EF%BC%88%E6%96%AD%E8%A8%80%EF%BC%89"><span class="nav-number">2.3.2.</span> <span class="nav-text">Assert（断言）</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Junit3-x%E4%B8%8E4-x%E5%8C%BA%E5%88%AB"><span class="nav-number">2.4.</span> <span class="nav-text">Junit3.x与4.x区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Failure%E4%B8%8EError%E5%8C%BA%E5%88%AB"><span class="nav-number">2.5.</span> <span class="nav-text">Failure与Error区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B8%B8%E7%94%A8%E6%B3%A8%E8%A7%A3"><span class="nav-number">2.6.</span> <span class="nav-text">常用注解</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F"><span class="nav-number">2.7.</span> <span class="nav-text">执行顺序</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%A7%84%E8%8C%83"><span class="nav-number">2.8.</span> <span class="nav-text">规范</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BF%90%E8%A1%8C%E5%99%A8Runner"><span class="nav-number">2.9.</span> <span class="nav-text">运行器Runner</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8F%82%E6%95%B0%E5%8C%96%E6%B5%8B%E8%AF%95"><span class="nav-number">2.9.1.</span> <span class="nav-text">参数化测试</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Mock-Stub"><span class="nav-number">3.</span> <span class="nav-text">Mock&#x2F;Stub</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E8%AF%84%E4%BC%B0"><span class="nav-number">4.</span> <span class="nav-text">单元测试评估</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E4%BB%BB%E5%8A%A1"><span class="nav-number">4.1.</span> <span class="nav-text">单元测试任务</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BB%A3%E7%A0%81%E8%A6%86%E7%9B%96%E7%8E%87"><span class="nav-number">4.2.</span> <span class="nav-text">代码覆盖率</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%AF%AD%E5%8F%A5%E8%A6%86%E7%9B%96-StatementCoverage"><span class="nav-number">4.2.1.</span> <span class="nav-text">语句覆盖(StatementCoverage)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%A4%E5%AE%9A%E8%A6%86%E7%9B%96-DecisionCoverage"><span class="nav-number">4.2.2.</span> <span class="nav-text">判定覆盖(DecisionCoverage)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%9D%A1%E4%BB%B6%E8%A6%86%E7%9B%96-ConditionCoverage-%E5%AE%83%E5%BA%A6%E9%87%8F%E5%88%A4%E5%AE%9A%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E5%AD%90%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%BB%93%E6%9E%9Ctrue%E5%92%8Cfalse%E6%98%AF%E5%90%A6%E8%A2%AB%E6%B5%8B%E8%AF%95%E5%88%B0%E4%BA%86%E3%80%82%E4%B8%BA%E4%BA%86%E8%AF%B4%E6%98%8E%E5%88%A4%E5%AE%9A%E8%A6%86%E7%9B%96%E5%92%8C%E6%9D%A1%E4%BB%B6%E8%A6%86%E7%9B%96%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%8C%E6%88%91%E4%BB%AC%E6%9D%A5%E4%B8%BE%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90%EF%BC%8C%E5%81%87%E5%A6%82%E6%88%91%E4%BB%AC%E7%9A%84%E8%A2%AB%E6%B5%8B%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B%EF%BC%9A"><span class="nav-number">4.2.3.</span> <span class="nav-text">条件覆盖(ConditionCoverage)它度量判定中的每个子表达式结果true和false是否被测试到了。为了说明判定覆盖和条件覆盖的区别，我们来举一个例子，假如我们的被测代码如下：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%B7%AF%E5%BE%84%E8%A6%86%E7%9B%96-PathCoverage"><span class="nav-number">4.2.4.</span> <span class="nav-text">路径覆盖(PathCoverage)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Jacoco"><span class="nav-number">4.2.5.</span> <span class="nav-text">Jacoco</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#Java-Agent%E5%B5%8C%E5%85%A5"><span class="nav-number">4.2.5.1.</span> <span class="nav-text">Java Agent嵌入</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Java-Report"><span class="nav-number">4.2.5.2.</span> <span class="nav-text">Java Report</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%85%B6%E4%BB%96-Android"><span class="nav-number">5.</span> <span class="nav-text">其他(Android)</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#test%E4%B8%8EandroidTest%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-number">5.1.</span> <span class="nav-text">test与androidTest的区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Studio%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E6%AD%A5%E9%AA%A4"><span class="nav-number">5.2.</span> <span class="nav-text">Studio单元测试步骤</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF"><span class="nav-number">5.3.</span> <span class="nav-text">常见错误</span></a></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="LinBinghe"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">LinBinghe</p>
  <div class="site-description" itemprop="description">Knowledge as Action</div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives">
          <span class="site-state-item-count">39</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
        <span class="site-state-item-count">13</span>
        <span class="site-state-item-name">categories</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
        <span class="site-state-item-count">60</span>
        <span class="site-state-item-name">tags</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author site-overview-item animated">
      <span class="links-of-author-item">
        <a href="https://github.com/LinBinghe" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;LinBinghe" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i></a>
      </span>
      <span class="links-of-author-item">
        <a href="https://www.zhihu.com/people/shawn_lam" title="Zhihu → https:&#x2F;&#x2F;www.zhihu.com&#x2F;people&#x2F;shawn_lam" rel="noopener" target="_blank"><i class="fab fa-zhihu fa-fw"></i></a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:linbinghe@gmail.com" title="E-Mail → mailto:linbinghe@gmail.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i></a>
      </span>
  </div>



        </div>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="Back to top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-Hans">
    <link itemprop="mainEntityOfPage" href="http://www.nilstorm.com/2017/3.698e+119.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="LinBinghe">
      <meta itemprop="description" content="Knowledge as Action">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Lam's Blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          关于Java单元测试，你需要知道的一切
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">Posted on</span>

      <time title="Created: 2017-03-04 13:54:47" itemprop="dateCreated datePublished" datetime="2017-03-04T13:54:47+08:00">2017-03-04</time>
    </span>
      <span class="post-meta-item">
        <span class="post-meta-item-icon">
          <i class="far fa-calendar-check"></i>
        </span>
        <span class="post-meta-item-text">Edited on</span>
        <time title="Modified: 2021-06-06 16:08:18" itemprop="dateModified" datetime="2021-06-06T16:08:18+08:00">2021-06-06</time>
      </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">In</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/" itemprop="url" rel="index"><span itemprop="name">单元测试</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h1><p>单元测试是先mock一些正常边界异常条件来对接口进行操作，并且期望接口返回什么内容，最后接口实现了之后再重新测试一遍。<br>TDD：Test-Driven Development，测试驱动开发模式——旨在强调在开发功能代码之前，先编写测试代码。开发未动，测试先行。<br><span id="more"></span><br><strong><em>为什么我们要进行单元测试：</em></strong><br>最后才修改一个 bug 的代价是在 bug 产生时修改它的代价的10倍。——《快速软件开发》<br>测试任何可能的错误。单元测试不是用来证明您是对的，而是为了证明您没有错。<br><em>单元测试是编写测试代码，用来检测特定的、明确的、细颗粒的功能。单元测试并不一定保证程序功能是正确的，更不保证整体业务是准备的。</em><br><em>单元测试不仅仅用来保证当前代码的正确性，更重要的是用来保证代码修复、改进或重构之后的正确性。</em></p>
<h1 id="JUNIT"><a href="#JUNIT" class="headerlink" title="JUNIT"></a>JUNIT</h1><p>JUnit 是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架（regression testing framework）。JUnit 测试是程序员测试，即所谓白盒测试。它是一个 Java 语言的测试框架，多数 Java 的开发环境都已经集成了 JUnit 作为单元测试的工具。</p>
<h2 id="特性"><a href="#特性" class="headerlink" title="特性"></a>特性</h2><ul>
<li>用于测试期望结果的断言（Assertion）</li>
<li>用于共享共同测试数据的测试工具</li>
<li>用于方便的组织和运行测试的测试套件</li>
<li>图形和文本的测试运行器</li>
</ul>
<h2 id="基本流程"><a href="#基本流程" class="headerlink" title="基本流程"></a>基本流程</h2><ul>
<li>写测试类并继承 TestCase 类</li>
<li>写测试方法 testXXX()， 测试方法必须以 test 开头</li>
<li>写测试套件类，将 test case 加入到 test suite， 如果没有为 test case 写 test suite 的话，系统会默认为每个 test case 生成一个 test suite</li>
<li>运行JUnit Test 进行测试</li>
</ul>
<h2 id="剖析概念"><a href="#剖析概念" class="headerlink" title="剖析概念"></a>剖析概念</h2><h3 id="TestXXX"><a href="#TestXXX" class="headerlink" title="TestXXX"></a>TestXXX</h3><ul>
<li>TestCase（测试用例）</li>
</ul>
<p>当一个类继承 JUnit 的 TestCase 类，即成为一个测试类，而且，测试类中的方法必须以 test 开头，比如：testAdd() 等。</p>
<ul>
<li>TestSuite（测试套件）</li>
</ul>
<p>TestSuite 是一组测试，目的在于将相关的测试用例归入一组。当执行一个 Test Suite 时，就会执行组内所有的测试方法，这就避免了繁琐的测试步骤。当然，如果没有为 test case 写 test suite 的话，系统会默认为每个 test case 生成一个 test suite。</p>
<h3 id="Assert（断言）"><a href="#Assert（断言）" class="headerlink" title="Assert（断言）"></a>Assert（断言）</h3><p>Assert 用于检查条件是否成立，当条件成立则 Assert 方法通过，否则会抛出异常。例如，Assert.assertEquals(3, result); 判断 result 是否跟期望的3想等，如果想等则通过，否则测试失败。<br>主要有如下几个断言方法：</p>
<ul>
<li>assertTrue/False（）：判断一个条件是 true 还是 false。</li>
<li>fail（）：失败，可以有消息，也可以没有消息。</li>
<li>assertEquals（）：判断是否想等，可以指定输出错误信息。注意不同数据类型所使用的 assertEquals 方法参数有所不同。</li>
<li>assertNotNull/Null（）：判断一个对象是否为空。</li>
<li>assertSame/NotSame（）：判断两个对象是否指向同一个对象。</li>
<li>failNotSame/failNotEquals（）：当不指向同一个内存地址或者不相等的时候，输出错误信息。错误信息为指定的格式。</li>
<li>setUp<br>每次测试方法执行之前，都会执行 setUp 方法，此方法用于进行一些固定的准备工作，比如，实例化对象，打开网络连接等。</li>
<li>tearDown<br>每次测试方法执行之后，都会执行 tearDown 方法，此方法用于进行一些固定的善后工作，比如，关闭网络连接等。</li>
</ul>
<h2 id="Junit3-x与4-x区别"><a href="#Junit3-x与4-x区别" class="headerlink" title="Junit3.x与4.x区别"></a>Junit3.x与4.x区别</h2><p><img src="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk12.png" alt=""></p>
<h2 id="Failure与Error区别"><a href="#Failure与Error区别" class="headerlink" title="Failure与Error区别"></a>Failure与Error区别</h2><p><img src="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk13.png" alt=""></p>
<p><strong>单元测试的失败（Failure）与测试出现了错误（Error）</strong><br>JUnit 将测试失败的情况分为两种：Failure 和 Error 。 Failure 一般是由单元测试使用的断言方法判断失败引起的，它表示在测试点发现了问题（程序中的 bug）；而 Error 则是有代码异常引起的，这是测试目的之外的发现，它可能产生于测试代码本身的错误（也就是说，编写的测试代码有问题），也可能是被测试代码中的一个隐藏 bug 。不过，一般情况下是第一种情况。</p>
<h2 id="常用注解"><a href="#常用注解" class="headerlink" title="常用注解"></a>常用注解</h2><ul>
<li>@Before<br>初始化方法，在任何一个测试方法执行之前，必须执行的代码。对比 JUnit 3 ，和 setUp（）方法具有相同的功能。在该注解的方法中，可以进行一些准备工作，比如初始化对象，打开网络连接等。</li>
<li>@After<br>释放资源，在任何一个测试方法执行之后，需要进行的收尾工作。对比 JUnit 3 ，和 tearDown（）方法具有相同的功能。</li>
<li>@Test<br>测试方法，表明这是一个测试方法。在 JUnit 中将会自动被执行。对与方法的声明也有如下要求：名字可以随便取，没有任何限制，但是返回值必须为 void ，而且不能有任何参数。如果违反这些规定，会在运行时抛出一个异常。不过，为了培养一个好的编程习惯，我们一般在测试的方法名上加 test ，比如：testAdd（）。<br>同时，该 Annotation（@Test） 还可以测试期望异常和超时时间，如 @Test（timeout=100），我们给测试函数设定一个执行时间，超过这个时间（100毫秒），他们就会被系统强行终止，并且系统还会向你汇报该函数结束的原因是因为超时，这样你就可以发现这些 bug 了。而且，它还可以测试期望的异常，例如，我们刚刚的那个空指针异常就可以这样：@Test(expected=NullPointerException.class)，此时如果出现空指针异常，反正会认为测试通过</li>
</ul>
<p><img src="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk14.png" alt=""></p>
<ul>
<li>@Ignore<br>忽略的测试方法，标注的含义就是“某些方法尚未完成，咱不参与此次测试”；这样的话测试结果就会提示你有几个测试被忽略，而不是失败。一旦你完成了相应的函数，只需要把 @Ignore 注解删除即可，就可以进行正常测试了。</li>
<li>@BeforeClass<br>针对所有测试，也就是整个测试类中，在所有测试方法执行前，都会先执行由它注解的方法，而且只执行一次。当然，需要注意的是，修饰符必须是 public static void xxxx ；此 Annotation 是 JUnit 4 新增的功能。</li>
<li>@AfterClass<br>针对所有测试，也就是整个测试类中，在所有测试方法都执行完之后，才会执行由它注解的方法，而且只执行一次。当然，需要注意的是，修饰符也必须是 public static void xxxx ；此 Annotation 也是 JUnit 4 新增的功能，与 @BeforeClass 是一对。</li>
</ul>
<h2 id="执行顺序"><a href="#执行顺序" class="headerlink" title="执行顺序"></a>执行顺序</h2><p>所以，在 JUnit 4 中，单元测试用例的执行顺序为：</p>
<p><img src="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk15.png" alt=""></p>
<p>每一个测试方法的调用顺序为：</p>
<p><img src="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk16.png" alt=""></p>
<h2 id="规范"><a href="#规范" class="headerlink" title="规范"></a>规范</h2><ul>
<li>单元测试代码应位于单独的 Source Folder 下<br>此 Source Folder 通常为 test ，这样可以方便的管理业务代码与测试代码。</li>
<li>测试类应该与被测试类位于同一 package名 下</li>
<li>选择有意义的测试方法名<br>无论是 JUnit 4 ，还是 JUnit 3 ，单元测试方法名均需使用 test&lt;待测试方法名称&gt;[概要描述]</li>
<li>保存测试的独立性<br>每项单元测试都必须独立于其他所有单元测试而运行，因为单元测试需能以任何顺序运行。</li>
<li>为暂时未实现的测试代码忽略（@Ignore）或抛出失败（fail）<br>在 JUnit 4 中，可以在测试方法上使用注解 @Ignore 。在 JUnit 3 中，可以在未实现的测试方法中使用 fail(“测试方法未实现”); 以告知失败是因为测试方法未实现。</li>
<li>在调用断言（assert）方法时给出失败的原因<br>在使用断言方法时，请使用带有 message 参数的 API ，并在调用时给出失败时的原因描述，如 assertNotNull（”对象为空”, new Object()）。</li>
</ul>
<h2 id="运行器Runner"><a href="#运行器Runner" class="headerlink" title="运行器Runner"></a>运行器Runner</h2><p>类注解@RunWith，指定不同的类可以改变测试类的行为</p>
<h3 id="参数化测试"><a href="#参数化测试" class="headerlink" title="参数化测试"></a>参数化测试</h3><p>主要是针对一些相同功能却要进行多组参数测试的情况，开发步骤如下：</p>
<ol>
<li>参数化测试的类和普通测试类不同，要用特殊的Runner，类注解需要改为@RunWith(Parameterized.class)</li>
<li>定义该测试类的成员变量，一个放测试参数，另一个放该参数产生的预期结果</li>
<li>定义测试数据集合方法 public static Collection data() {…}，注意该方法要用@Parameters修饰（数据格式为二维数组）</li>
<li><p>定义带参数的构造函数，注意定义数据集合时，要和构造函数参数次序一致</p>
<pre><code>
//指定@RunWith  
@RunWith(Parameterized.class)  
public class ParamTest &#123;  

  //定义成员变量，i为测试参数，j为测试结果  
  private int i;  
  private int j;  

  //构造函数  
  public ParamTest(int i, int j) &#123;  
      super();  
      this.i = i;  
      this.j = j;  
  &#125;  

  //测试数据集合，注意使用的注解，数据结构及次序  
  @Parameters  
  public static Collection data() &#123;  
      return Arrays.asList(new Object[][]&#123;&#123;1,2&#125;,&#123;3,4&#125;,&#123;4,6&#125;&#125;);  
  &#125;  
  @Test  
  public void testMethod1() &#123;  
      System.out.println(i);  
      System.out.println(j);  
      //简单测试，只测试参数加1会不会等于预期结果  
      Assert.assertEquals(i+1, j);  
  &#125;  
&#125;  
</code></pre>

</li>
</ol>
<h1 id="Mock-Stub"><a href="#Mock-Stub" class="headerlink" title="Mock/Stub"></a>Mock/Stub</h1><p>如果你真的去把所有获取测试你的服务的前置条件的代码都完成，然后再写你的单元测试代码的话，这就不是单元测试了，这叫自动化测试，所以我们需要mock。<br>Mockito是Google Code上的一个开源项目，只需要在“运行测试代码”之前对接口进行Stub，也即设置方法的返回值或抛出的异常，然后直接运行测试代码，运行期间调用Mock的方法，会返回预先设置的返回值或抛出异常，最后再对测试代码进行验证。<br>Mockito创建mock对象不能对final，Anonymous ，primitive类和静态方法进行mock， powermock通过修改字节码来支持了此功能。</p>
<ul>
<li><p><strong>验证调用行为</strong></p>
<pre><code>
import static org.mockito.Mockito.*;  

//创建Mock  
List mockedList = mock(List.class);  

//使用Mock对象  
mockedList.add("one");  
mockedList.clear();  

//验证行为  
verify(mockedList).add("one");  
verify(mockedList).clear();  
</code></pre>
</li>
<li><p><strong>对Mock对象进行Stub</strong></p>
<pre><code>
//也可以Mock具体的类，而不仅仅是接口  
LinkedList mockedList = mock(LinkedList.class);  

//Stub  
when(mockedList.get(0)).thenReturn("first"); // 设置返回值  
when(mockedList.get(1)).thenThrow(new RuntimeException()); // 抛出异常  

//第一个会打印 "first"  
System.out.println(mockedList.get(0));  

//接下来会抛出runtime异常  
System.out.println(mockedList.get(1));  

//接下来会打印"null",这是因为没有stub get(999)  
System.out.println(mockedList.get(999));  

// 可以选择性地验证行为，比如只关心是否调用过get(0)，而不关心是否调用过get(1)  
verify(mockedList).get(0);  
</code></pre>

</li>
</ul>
<p><strong><em>注意：android SDK中的库，大部分都只定义了接口而在jvm直接运行时是没有实现的，需要在虚拟机或者真机上运行，所以尽量使用自己导入的库，因为这些库带有具体实现，测试方法才能有效。</em></strong></p>
<h1 id="单元测试评估"><a href="#单元测试评估" class="headerlink" title="单元测试评估"></a>单元测试评估</h1><h2 id="单元测试任务"><a href="#单元测试任务" class="headerlink" title="单元测试任务"></a>单元测试任务</h2><ol>
<li>接口功能测试：用来保证接口功能的正确性。</li>
<li>局部数据结构测试（不常用）：用来保证接口中的数据结构是正确的<ol>
<li>比如变量有无初始值</li>
<li>变量是否溢出</li>
</ol>
</li>
<li>边界条件测试<ol>
<li>变量没有赋值（即为NULL）</li>
<li>变量是数值（或字符)<ol>
<li>主要边界：最小值，最大值，无穷大（对于DOUBLE等）</li>
<li>溢出边界（期望异常或拒绝服务）：最小值-1，最大值+1</li>
<li>临近边界：最小值+1，最大值-1</li>
</ol>
</li>
<li>变量是字符串<ol>
<li>引用“字符变量”的边界</li>
<li>空字符串</li>
<li>对字符串长度应用“数值变量”的边界</li>
</ol>
</li>
<li>变量是集合<ol>
<li>空集合</li>
<li>对集合的大小应用“数值变量”的边界</li>
<li>调整次序：升序、降序</li>
</ol>
</li>
<li>变量有规律<ol>
<li>比如对于Math.sqrt，给出n^2-1，和n^2+1的边界</li>
</ol>
</li>
</ol>
</li>
<li>所有独立执行通路测试：保证每一条代码，每个分支都经过测试<ol>
<li>代码覆盖率<ol>
<li>语句覆盖：保证每一个语句都执行到了</li>
<li>判定覆盖（分支覆盖）：保证每一个分支都执行到</li>
<li>条件覆盖：保证每一个条件都覆盖到true和false（即if、while中的条件语句）</li>
<li>路径覆盖：保证每一个路径都覆盖到</li>
</ol>
</li>
<li>相关软件<ol>
<li>Cobertura：语句覆盖</li>
<li>Emma: Eclipse插件Eclemma</li>
</ol>
</li>
</ol>
</li>
<li>各条错误处理通路测试：保证每一个异常都经过测试</li>
</ol>
<h2 id="代码覆盖率"><a href="#代码覆盖率" class="headerlink" title="代码覆盖率"></a>代码覆盖率</h2><p>在做单元测试时，代码覆盖率常常被拿来作为衡量测试好坏的指标，甚至，用代码覆盖率来考核测试任务完成情况，比如，代码覆盖率必须达到80％或 90％。于是乎，测试人员费尽心思设计案例覆盖代码。用代码覆盖率来衡量，有利也有有弊。<br>代码覆盖率 ＝ 代码的覆盖程度，一种度量方式。</p>
<h3 id="语句覆盖-StatementCoverage"><a href="#语句覆盖-StatementCoverage" class="headerlink" title="语句覆盖(StatementCoverage)"></a>语句覆盖(StatementCoverage)</h3><p>又称行覆盖(LineCoverage)，段覆盖(SegmentCoverage)，基本块覆盖(BasicBlockCoverage)，这是最常用也是最常见的一种覆盖方式，就是度量被测代码中每个可执行语句是否被执行到了。 需要注意的是，单独一行的花括号｛｝ 也常常被统计进去。 语句覆盖常常被人指责为“最弱的覆盖”，它只管覆盖代码中的执行语句，却不考虑各种分支的组合等等。 假如你的上司只要求你达到语句覆盖，那么你可以省下很多功夫，但是，换来的确实测试效果的不明显，很难更多地发现代码中的问题。<br>这里举一个不能再简单的例子，我们看下面的被测试代码：</p>
<p><pre><code>
int foo(int a, int b)
&#123;
   return  a / b;
&#125;
</code></pre><br>假如我们的测试人员编写如下测试案例：</p>
<p><pre><code>TeseCase: a = 10, b = 5</code></pre><br>以上代码当b=0时程序异常，但是语句覆盖率为100%</p>
<h3 id="判定覆盖-DecisionCoverage"><a href="#判定覆盖-DecisionCoverage" class="headerlink" title="判定覆盖(DecisionCoverage)"></a>判定覆盖(DecisionCoverage)</h3><p>又称分支覆盖(BranchCoverage)，所有边界覆盖(All-EdgesCoverage)，基本路径覆盖(BasicPathCoverage)，判定路径覆盖(Decision-Decision-Path)。它度量程序中每一个判定的分支是否都被测试到了。 这句话是需要进一步理解的，应该非常容易和下面说到的条件覆盖混淆。因此我们直接介绍第三种覆盖方式，然后和判定覆盖一起来对比，就明白两者是怎么回事了。</p>
<h3 id="条件覆盖-ConditionCoverage-它度量判定中的每个子表达式结果true和false是否被测试到了。为了说明判定覆盖和条件覆盖的区别，我们来举一个例子，假如我们的被测代码如下："><a href="#条件覆盖-ConditionCoverage-它度量判定中的每个子表达式结果true和false是否被测试到了。为了说明判定覆盖和条件覆盖的区别，我们来举一个例子，假如我们的被测代码如下：" class="headerlink" title="条件覆盖(ConditionCoverage)它度量判定中的每个子表达式结果true和false是否被测试到了。为了说明判定覆盖和条件覆盖的区别，我们来举一个例子，假如我们的被测代码如下："></a>条件覆盖(ConditionCoverage)它度量判定中的每个子表达式结果true和false是否被测试到了。为了说明判定覆盖和条件覆盖的区别，我们来举一个例子，假如我们的被测代码如下：</h3><p><pre><code>
int foo(int a, int b)
&#123;
    if (a < 10 || b < 10) // 判定
    &#123;
        return 0; // 分支一
    &#125;
    else
    &#123;
        return 1; // 分支二
    &#125;
&#125;
</code></pre><br>设计判定覆盖案例时，我们只需要考虑判定结果为true和false两种情况，因此，我们设计如下的案例就能达到判定覆盖率100％：</p>
<p><pre><code>
TestCaes1: a = 5, b ＝ 任意数字  覆盖了分支一
TestCaes2: a = 15, b = 15          覆盖了分支二
</code></pre><br> 设计条件覆盖案例时，我们需要考虑判定中的每个条件表达式结果，为了覆盖率达到100％，我们设计了如下的案例：</p>
<p><pre><code>
TestCase1: a = 5, b = 5       true,  true
TestCase4: a = 15, b = 15   false, false
</code></pre><br>通过上面的例子，我们应该很清楚了判定覆盖和条件覆盖的区别。需要特别注意的是：条件覆盖不是将判定中的每个条件表达式的结果进行排列组合，而是只要每个条件表达式的结果true和false测试到了就OK了。因此，我们可以这样推论：完全的条件覆盖并不能保证完全的判定覆盖。比如上面的例子，假如我设计的案例为：</p>
<p><pre><code>
TestCase1: a = 5, b = 15  true,  false   分支一
TestCase1: a = 15, b = 5  false, true    分支一
</code></pre><br>我们看到，虽然我们完整的做到了条件覆盖，但是我们却没有做到完整的判定覆盖，我们只覆盖了分支一。</p>
<h3 id="路径覆盖-PathCoverage"><a href="#路径覆盖-PathCoverage" class="headerlink" title="路径覆盖(PathCoverage)"></a>路径覆盖(PathCoverage)</h3><p>又称断言覆盖(PredicateCoverage)。它度量了是否函数的每一个分支都被执行了，测试函数中所有可能的路径。 这句话也非常好理解，就是所有可能的分支都执行一遍，有多个分支嵌套时，需要对多个分支进行排列组合，可想而知，测试路径随着分支的数量指数级别增加。比如下面的测试代码中有两个判定分支：</p>
<p><pre><code>
int foo(int a, int b)
&#123;
    int nReturn = 0;
    if (a < 10)
    &#123;// 分支一
        nReturn += 1;
    &#125;
    if (b < 10)
    &#123;// 分支二
        nReturn += 10;
    &#125;
    return nReturn;
&#125;
</code></pre><br>对上面的代码，我们分别针对我们前三种覆盖方式来设计测试案例：</p>
<ul>
<li><p><strong><em>语句覆盖</em></strong><br><pre><code>
TestCase a = 5, b = 5   nReturn = 11
</code></pre><br>语句覆盖率100％</p>
</li>
<li><p><strong><em>判定覆盖</em></strong><br><pre><code>
TestCase1 a = 5,   b = 5     nReturn = 11
TestCase2 a = 15, b = 15   nReturn = 0
</code></pre><br>判定覆盖率100％ </p>
</li>
<li><p><strong><em>条件覆盖</em></strong><br><pre><code>
TestCase1 a = 5,   b = 15   nReturn = 1
TestCase2 a = 15, b = 5     nReturn = 10
</code></pre><br>条件覆盖率100％ </p>
</li>
</ul>
<p>我们看到，上面三种覆盖率结果看起来都很酷！都达到了100％！主管可能会非常的开心，但是，让我们再去仔细的看看，上面被测代码中，nReturn的结果一共有四种可能的返回值：0，1，10，11，而我们上面的针对每种覆盖率设计的测试案例只覆盖了部分返回值，因此，可以说使用上面任一覆盖方式，虽然覆盖率达到了100%，但是并没有测试完全。接下来我们来看看针对路径覆盖设计出来的测试案例：</p>
<p><pre><code>
TestCase1 a = 5,    b = 5     nReturn = 0
TestCase2 a = 15,  b = 5     nReturn = 1
TestCase3 a = 5,    b = 15   nReturn = 10
TestCase4 a = 15,  b = 15   nReturn = 11
</pre>&lt;/code&gt;<br>路径覆盖率100％<br>太棒了！路径覆盖将所有可能的返回值都测试到了。这也正是它被很多人认为是“最强的覆盖”的原因了。<br>还有一些其他的覆盖方式，如：循环覆盖(LoopCoverage)，它度量是否对循环体执行了零次，一次和多余一次循环。剩下一些其他覆盖方式就不介绍了。</p>
<h3 id="Jacoco"><a href="#Jacoco" class="headerlink" title="Jacoco"></a>Jacoco</h3><p>Jacoco可以嵌入到Ant、Maven中，也可以使用Java Agent技术监控任意Java程序，也可以使用Java Api来定制功能。<br>Jacoco会监控JVM中的调用，生成监控结果（默认保存在jacoco.exec文件中），然后分析此结果，配合源代码生成覆盖率报告。需要注意的是：监控和分析这两步，必须使用相同的Class文件，否则由于Class不同，而无法定位到具体的方法，导致覆盖率均为0%。</p>
<h4 id="Java-Agent嵌入"><a href="#Java-Agent嵌入" class="headerlink" title="Java Agent嵌入"></a>Java Agent嵌入</h4><p>首先，需要下载jacocoagent.jar文件，然后在Java程序启动参数后面加上 -javaagent:[yourpath/]jacocoagent.jar=[option1]=[value1],[option2]=[value2]，具体的options可以在此页面找到。默认会在JVM关闭时（注意不能是kill -9），输出监控结果到jacoco.exec文件中，也可以通过socket来实时地输出监控报告（可以在Example代码中找到简单实现）。</p>
<h4 id="Java-Report"><a href="#Java-Report" class="headerlink" title="Java Report"></a>Java Report</h4><p>可以使用Ant、Mvn或Eclipse来分析jacoco.exec文件，也可以通过API来分析。</p>
<p><pre><code>
public void createReport() throws Exception {
    // 读取监控结果  
    final FileInputStream fis = new FileInputStream(new File("jacoco.exec"));
    final ExecutionDataReader executionDataReader = new ExecutionDataReader(fis);
    // 执行数据信息  
    ExecutionDataStore executionDataStore = new ExecutionDataStore();
    // 会话信息  
    SessionInfoStore sessionInfoStore = new SessionInfoStore();
    executionDataReader.setExecutionDataVisitor(executionDataStore);
    executionDataReader.setSessionInfoVisitor(sessionInfoStore);
    while (executionDataReader.read()) {}
    fis.close();
    // 分析结构  
    final CoverageBuilder coverageBuilder = new CoverageBuilder();
    final Analyzer analyzer = new Analyzer(executionDataStore, coverageBuilder);
    // 传入监控时的Class文件目录，注意必须与监控时的一样  
    File classesDirectory = new File("classes");
    analyzer.analyzeAll(classesDirectory);
    IBundleCoverage bundleCoverage = coverageBuilder.getBundle("Title");
    // 输出报告  
    File reportDirectory = new File("report"); // 报告所在的目录  
    final HTMLFormatter htmlFormatter = new HTMLFormatter();  // HTML格式  
    final IReportVisitor visitor = htmlFormatter.createVisitor(new FileMultiReportOutput(reportDirectory));
    // 必须先调用visitInfo  
    visitor.visitInfo(sessionInfoStore.getInfos(), executionDataStore.getContents());
    File sourceDirectory = new File("src"); // 源代码目录  
    // 遍历所有的源代码  
    // 如果不执行此过程，则在报告中只能看到方法名，但是无法查看具体的覆盖（因为没有源代码页面）  
    visitor.visitBundle(bundleCoverage, new DirectorySourceFileLocator(sourceDirectory, "utf-8", 4));
    // 执行完毕  
    visitor.visitEnd();
}
</pre>&lt;/code&gt;<br><em>Android testDebug任务找不到的原因<a target="_blank" rel="noopener" href="http://stackoverflow.com/questions/31937815/task-with-name-testdebug-not-found-in-project-module">http://stackoverflow.com/questions/31937815/task-with-name-testdebug-not-found-in-project-module</a></em></p>
<h1 id="其他-Android"><a href="#其他-Android" class="headerlink" title="其他(Android)"></a>其他(Android)</h1><h2 id="test与androidTest的区别"><a href="#test与androidTest的区别" class="headerlink" title="test与androidTest的区别"></a>test与androidTest的区别</h2><ol>
<li>test为单元测试，androidTest为与界面有关的测试，包括自动化测试</li>
<li>gradle项目依赖，testCompile与androidTestCompile</li>
<li>androidTest需要在模拟器或者真机上运行<br><a target="_blank" rel="noopener" href="http://stackoverflow.com/questions/29021331/confused-about-testcompile-and-androidtestcompile-in-android-gradle">http://stackoverflow.com/questions/29021331/confused-about-testcompile-and-androidtestcompile-in-android-gradle</a></li>
</ol>
<h2 id="Studio单元测试步骤"><a href="#Studio单元测试步骤" class="headerlink" title="Studio单元测试步骤"></a>Studio单元测试步骤</h2><p>创建项目——根据需要testCompile或者androidTestCompile相应的测试支持库——设置Build Variant为相应的测试环境——Edit Configuration ——测试驱动开发，可以先写空实现的接口，通过IDE的快捷操作方式自动生成相应目录下的测试类——运行相应的TestCase</p>
<h2 id="常见错误"><a href="#常见错误" class="headerlink" title="常见错误"></a>常见错误</h2><ol>
<li>No tests found in …<br>如果使用安卓自身的Instrumentation相关的测试，studio自动生成的TestCase不会去继承TestCase，是不会被Runner所判断为测试用例的，所以自然找不到测试，根据需要自己选择要继承的基类<br>单元测试不需要使用Instrumentation，<br>This is where you need to select “Build Variants” on the left of Android Studio and make sure “Unit Tests” is selected<br>一定要选择这个选项，否则所有的步骤都是以Instrumentation框架进行，大多用于自动化测试</li>
<li></li>
</ol>
<p><img src="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk17.png" alt=""></p>
<p><img src="https://raw.githubusercontent.com/LinBinghe/lam-images/master/wx23xkk18.png" alt=""></p>
<hr>
<p><strong>版权声明</strong></p>
<p><img src="https://tva1.sinaimg.cn/large/007S8ZIlgy1gee6wkfo69j30e9026gm4.jpg" alt="Creative Commons BY-NC-ND 4.0 International License"></p>
<p><a target="_blank" rel="noopener" href="http://linbinghe.me/">Lam’s Blog</a> by <a target="_blank" rel="noopener" href="http://linbinghe.me/">Binghe Lin</a> is licensed under a <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons BY-NC-ND 4.0 International License</a>.<br>由<a target="_blank" rel="noopener" href="http://linbinghe.me/">林炳河</a>创作并维护的<a target="_blank" rel="noopener" href="http://linbinghe.me/">Lam’s Blog</a>采用<a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">创作共用保留署名-非商业-禁止演绎4.0国际许可证</a>。</p>
<p>本文首发于<a target="_blank" rel="noopener" href="http://linbinghe.me/">Lam’s Blog - Knowledeg as Action</a>，版权所有，侵权必究。</p>
<p>本文永久链接：<a target="_blank" rel="noopener" href="http://codinglife.me/2017/3.698e+119.html">http://codinglife.me/2017/3.698e+119.html</a></p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Java/" rel="tag"># Java</a>
              <a href="/tags/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/" rel="tag"># 单元测试</a>
              <a href="/tags/Junit/" rel="tag"># Junit</a>
              <a href="/tags/Mock/" rel="tag"># Mock</a>
              <a href="/tags/%E8%A6%86%E7%9B%96%E7%8E%87/" rel="tag"># 覆盖率</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2017/55efffcd.html" rel="prev" title="利用bat实现Android的自动化编译">
                  <i class="fa fa-chevron-left"></i> 利用bat实现Android的自动化编译
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2017/7d558e92.html" rel="next" title="关于Java并发编程的总结">
                  关于Java并发编程的总结 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">LinBinghe</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/" rel="noopener" target="_blank">NexT.Gemini</a>
  </div>

    </div>
  </footer>

  
  <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script>

  






  





</body>
</html>
